package com.rp.data.tcp_ws.server_tcp;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.Channel;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.logging.LogLevel;
import io.netty.handler.logging.LoggingHandler;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;

/**
 * @author 90504
 */
@Slf4j
@Component
public class NettyServerTcp {

	private static NettyServerTcp nettyServerTcp;

	@PostConstruct
	public void init() {
		nettyServerTcp = this;
	}

	private static class SingletionNettyServer {
		static final NettyServerTcp instance = new NettyServerTcp();
	}

	public static NettyServerTcp getInstance() {
		return SingletionNettyServer.instance;
	}

	private EventLoopGroup bossGroup;
	private EventLoopGroup workerGroup;
	private ServerBootstrap bootstrap;
	private Channel channel;

	public NettyServerTcp() {
		// TODO Auto-generated method stub
		// EventLoopGroup是用来处理IO操作的多线程事件循环器
		// 负责接收客户端连接线程
		bossGroup = new NioEventLoopGroup();
		// 负责处理客户端i/o事件、task任务、监听任务组
		workerGroup = new NioEventLoopGroup();
		// 启动 NIO 服务的辅助启动类
		bootstrap = new ServerBootstrap();
		bootstrap.group(bossGroup, workerGroup);
		// 配置 Channel
		bootstrap.channel(NioServerSocketChannel.class);
		bootstrap.childHandler(new ServerIniterHandlerTcp());
		// BACKLOG用于构造服务端套接字ServerSocket对象，
		// 标识当服务器请求处理线程全满时，用于临时存放已完成三次握手的请求的队列的最大长度
		bootstrap.option(ChannelOption.SO_BACKLOG, 1024);
		// 是否启用心跳保活机制
		bootstrap.childOption(ChannelOption.SO_KEEPALIVE, true);
		bootstrap.handler(new LoggingHandler(LogLevel.INFO));
	}

	public void start(int port){
		try {
			// 绑定服务端口监听
			channel = bootstrap.bind(port).sync().channel();
			log.info("成功开启端口:" + port);
			// 服务器关闭监听
			/*
			 * channel.closeFuture().sync()实际是如何工作:
			 * channel.closeFuture()不做任何操作，只是简单的返回channel对象中的closeFuture对象，对于每个Channel对象，
			 * 都会有唯一的一个CloseFuture，用来表示关闭的Future，
			 * 所有执行channel.closeFuture().sync()就是执行的CloseFuturn的sync方法，从上面的解释可以知道，
			 * 这步是会将当前线程阻塞在CloseFuture上
			 */
			channel.closeFuture().sync();
		} catch (InterruptedException e) {
			e.printStackTrace();
		} finally {
			// 关闭事件流组
			bossGroup.shutdownGracefully();
			workerGroup.shutdownGracefully();
		}
	}
}
